﻿using System;
using Wizard.Compiler.Parsers;
using Wizard.Runtime;

namespace Wizard.Functions
{
    public class Compare<K> : Function<bool> where K : IComparable<K>
    {
        protected readonly IHasValue<K> mParam1;
        protected readonly IHasValue<K> mParam2;

        private readonly RecalcDelegate mRecalcDelegate;

        public Compare(IHasValue<K> param1, TokenType op, IHasValue<K> param2)
            : base("Compare", FunctionType.@operator)
        {
            mParam1 = param1;
            mParam2 = param2;
            // this is compile time

            switch (op)
            {
                case TokenType.operator_lt:
                    mRecalcDelegate = LessThan;
                    break;
                case TokenType.operator_le:
                    mRecalcDelegate = LessOrEqual;
                    break;
                case TokenType.operator_eq:
                    mRecalcDelegate = Equal;
                    break;
                case TokenType.operator_ge:
                    mRecalcDelegate = GreaterOrEqual;
                    break;
                case TokenType.operator_gt:
                    mRecalcDelegate = GreaterThan;
                    break;
                case TokenType.operator_ne:
                    mRecalcDelegate = NotEqual;
                    break;
            }
        }

        protected override bool RecalcValue(IRunContext context)
        {
            return mRecalcDelegate(context, mParam1.Value(context), mParam2.Value(context));
        }


        private bool LessThan(IRunContext context, K x, K y)
        {
            return x.CompareTo(y) < 0;
        }

        private bool LessOrEqual(IRunContext context, K x, K y)
        {
            return x.CompareTo(y) <= 0;
        }

        private bool Equal(IRunContext context, K x, K y)
        {
            return x.CompareTo(y) == 0;
        }

        private bool GreaterOrEqual(IRunContext context, K x, K y)
        {
            return x.CompareTo(y) >= 0;
        }

        private bool GreaterThan(IRunContext context, K x, K y)
        {
            return x.CompareTo(y) > 0;
        }

        private bool NotEqual(IRunContext context, K x, K y)
        {
            return x.CompareTo(y) != 0;
        }

        #region Nested type: RecalcDelegate

        private delegate bool RecalcDelegate(IRunContext context, K a, K b);

        #endregion
    }
}